﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using QW.Core.Exceptions;
using QW.Core.Helper;
using QW.Core.Log;

namespace QW.Core
{
    /// <summary>
    /// 注册器
    /// <para>注册策略</para>
    /// </summary>
    public class Registrar
    {
        #region 策略
        /// <summary>
        /// 策略是否已注册
        /// </summary>
        private static bool StrategiesRegisted = false;
        /// <summary>
        /// 注册策略所有dll
        /// </summary>
        public static List<Assembly> RegistStrategies()
        {
            List<Assembly> result = new List<Assembly>();
            if (!StrategiesRegisted)
            {
                result = Regist(IOHelper.GetMapPath("/Strategies"), true);
                StrategiesRegisted = true;
            }
            return result;
        }
        #endregion

        #region 注册dll
        /// <summary>
        /// 注册DLL
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="isDirectory">是否为目录</param>
        public static List<Assembly> Regist(string path, bool isDirectory)
        {
            List<Assembly> result = new List<Assembly>();
            if (isDirectory)
            {
                List<string> dllFiles = GetDirectoryDlls(path);
                foreach (string dllFileName in dllFiles)
                {
                    Assembly assembly = InstallDll(dllFileName);
                    result.Add(assembly);
                }
            }
            else
            {
                result.Add(InstallDll(path));
            }
            return result;
        }
        #endregion

        #region 卸载程序集
        /*
        /// <summary>
        /// 卸载程序集
        /// </summary>
        /// <param name="classFullName"></param>
        public static void UnInstallDlls(string classFullName)
        {
            try
            {
                Type sourceType = Type.GetType(classFullName);
                var obj = Activator.CreateInstance(sourceType);
                System.IO.Directory.Delete(pluginInfo.PluginDirectory, true);
            }
            catch
            {
                LogHelper.Warn(string.Format("卸载程序集{0}出错", classFullName));
            }
        }
*/
        #endregion

        #region 私有
        /// <summary>
        /// 获取目录下所有dll文件
        /// </summary>
        /// <param name="dir"></param>
        /// <returns></returns>
        private static List<string> GetDirectoryDlls(string dir)
        {
            if (!System.IO.Directory.Exists(dir))
                throw new QWBaseException("未能找到指定的目录:" + dir);

            //搜索当前目录(包括子目录)下所有dll文件
            string[] dllFiles = System.IO.Directory.GetFiles(dir, "*.dll", System.IO.SearchOption.AllDirectories);
            return dllFiles.ToList();
        }
        /// <summary>
        /// 加载(安装)dll 
        /// </summary>
        /// <param name="dllFileName"></param>
        /// <returns></returns>
        private static Assembly InstallDll(string dllFileName)
        {
            string newFileName = dllFileName;
            FileInfo fileInfo = new FileInfo(dllFileName);
            DirectoryInfo copyFolder;
            if (!string.IsNullOrWhiteSpace(AppDomain.CurrentDomain.DynamicDirectory))
            {
                //获取asp.net dll运行目录
                copyFolder = new DirectoryInfo(AppDomain.CurrentDomain.DynamicDirectory);
            }
            else
            {
                copyFolder = new DirectoryInfo(IOHelper.GetMapPath(""));
            }
            newFileName = copyFolder.FullName + "\\" + fileInfo.Name;

            Assembly assembly = null;
            try
            {
                try
                {
                    System.IO.File.Copy(dllFileName, newFileName, true);
                }
                catch
                {
                    //在某些情况下会出现"正由另一进程使用，因此该进程无法访问该文件"错误，所以先重命名再复制
                    System.IO.File.Move(newFileName, newFileName + Guid.NewGuid().ToString("N") + ".locked");
                    System.IO.File.Copy(dllFileName, newFileName, true);
                }
                assembly = Assembly.Load(AssemblyName.GetAssemblyName(newFileName));
            }
            catch (IOException ex)
            {
                LogHandler.Error("组件复制失败(" + dllFileName + ")！", ex);
            }
            catch (Exception ex)
            {
                LogHandler.Error("组件加载失败(" + dllFileName + ")！", ex);
            }
            return assembly;
        }
        #endregion
    }
}
